package com.example.job;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.domain.Lecture;
import com.example.domain.LectureRegistration;
import com.example.mapper.LectureMapper;
import com.example.mapper.LectureRegistrationMapper;
import com.example.service.LectureService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;

/**
 * 讲座定时任务
 * 
 * @author HP
 * @description 处理讲座相关的定时任务，包括过期报名处理、签到提醒等
 * @createDate 2025-08-26 22:30:00
 */
@Slf4j
@Component
public class LectureScheduledTask {

    @Resource
    private LectureService lectureService;
    
    @Resource
    private LectureMapper lectureMapper;
    
    @Resource
    private LectureRegistrationMapper lectureRegistrationMapper;

    /**
     * 处理过期讲座报名
     * 每10分钟执行一次，处理已过期的讲座报名记录
     */
    @Scheduled(fixedRate = 10 * 60 * 1000) // 10分钟
    public void processExpiredLectureRegistrations() {
        try {
            log.info("开始处理过期讲座报名...");
            
            Date now = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
            int processedCount = 0;
            
            // 查询所有已开始但报名状态仍为待签到的记录
            QueryWrapper<Lecture> lectureQuery = new QueryWrapper<>();
            lectureQuery.lt("start_time", now); // 讲座已开始
            lectureQuery.ne("lecture_status", 2); // 排除已结束的讲座
            lectureQuery.ne("lecture_status", 3); // 排除已取消的讲座
            
            List<Lecture> expiredLectures = lectureMapper.selectList(lectureQuery);
            
            for (Lecture lecture : expiredLectures) {
                // 查询该讲座下所有待签到的报名记录
                QueryWrapper<LectureRegistration> regQuery = new QueryWrapper<>();
                regQuery.eq("lecture_id", lecture.getId());
                regQuery.eq("registration_status", 0); // 待签到状态
                
                List<LectureRegistration> expiredRegistrations = lectureRegistrationMapper.selectList(regQuery);
                
                // 将过期报名标记为超时状态
                for (LectureRegistration registration : expiredRegistrations) {
                    // 检查是否超过签到时间窗口（讲座结束后30分钟）
                    Date signInDeadline = new Date(lecture.getEndTime().getTime() + 30 * 60 * 1000);
                    
                    if (now.after(signInDeadline)) {
                        registration.setRegistrationStatus(3); // 设置为超时状态
                        lectureRegistrationMapper.updateById(registration);
                        processedCount++;
                        
                        log.debug("处理过期报名：用户ID={}, 讲座ID={}, 讲座标题={}",
                                registration.getUserId(), lecture.getId(), lecture.getTitle());
                    }
                }
            }
            
            if (processedCount > 0) {
                log.info("处理过期讲座报名完成，共处理 {} 条记录", processedCount);
            }
        } catch (Exception e) {
            log.error("处理过期讲座报名失败", e);
        }
    }

    /**
     * 自动更新讲座状态
     * 每5分钟执行一次，根据时间自动更新讲座状态
     */
    @Scheduled(fixedRate = 5 * 60 * 1000) // 5分钟
    public void updateLectureStatus() {
        try {
            log.info("开始更新讲座状态...");
            
            Date now = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
            int updatedCount = 0;
            
            // 1. 将已开始的讲座状态更新为"进行中"
            QueryWrapper<Lecture> startedQuery = new QueryWrapper<>();
            startedQuery.le("start_time", now); // 开始时间 <= 当前时间
            startedQuery.gt("end_time", now);   // 结束时间 > 当前时间
            startedQuery.eq("lecture_status", 0); // 当前状态为"未开始"
            
            List<Lecture> startedLectures = lectureMapper.selectList(startedQuery);
            for (Lecture lecture : startedLectures) {
                lecture.setLectureStatus(1); // 设置为"进行中"
                lectureMapper.updateById(lecture);
                updatedCount++;
                log.debug("讲座已开始：ID={}, 标题={}", lecture.getId(), lecture.getTitle());
            }
            
            // 2. 将已结束的讲座状态更新为"已结束"
            QueryWrapper<Lecture> endedQuery = new QueryWrapper<>();
            endedQuery.lt("end_time", now); // 结束时间 < 当前时间
            endedQuery.in("lecture_status", 0, 1); // 当前状态为"未开始"或"进行中"
            
            List<Lecture> endedLectures = lectureMapper.selectList(endedQuery);
            for (Lecture lecture : endedLectures) {
                lecture.setLectureStatus(2); // 设置为"已结束"
                lectureMapper.updateById(lecture);
                updatedCount++;
                log.debug("讲座已结束：ID={}, 标题={}", lecture.getId(), lecture.getTitle());
            }
            
            if (updatedCount > 0) {
                log.info("讲座状态更新完成，共更新 {} 个讲座", updatedCount);
            }
        } catch (Exception e) {
            log.error("更新讲座状态失败", e);
        }
    }

    /**
     * 讲座签到提醒
     * 每小时执行一次，为即将开始的讲座发送签到提醒
     */
    @Scheduled(cron = "0 0 * * * ?") // 每小时执行
    public void sendLectureCheckInReminder() {
        try {
            log.info("开始检查讲座签到提醒...");
            
            Date now = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
            Date oneHourLater = new Date(now.getTime() + 60 * 60 * 1000); // 1小时后
            int reminderCount = 0;
            
            // 查询1小时内即将开始的讲座
            QueryWrapper<Lecture> upcomingQuery = new QueryWrapper<>();
            upcomingQuery.gt("start_time", now);          // 开始时间 > 当前时间
            upcomingQuery.le("start_time", oneHourLater); // 开始时间 <= 1小时后
            upcomingQuery.eq("lecture_status", 0);        // 状态为"未开始"
            
            List<Lecture> upcomingLectures = lectureMapper.selectList(upcomingQuery);
            
            for (Lecture lecture : upcomingLectures) {
                // 查询该讲座的所有报名用户
                QueryWrapper<LectureRegistration> regQuery = new QueryWrapper<>();
                regQuery.eq("lecture_id", lecture.getId());
                regQuery.eq("registration_status", 0); // 待签到状态
                
                List<LectureRegistration> registrations = lectureRegistrationMapper.selectList(regQuery);
                
                if (!registrations.isEmpty()) {
                    // 这里可以发送提醒通知（邮件、短信、站内信等）
                    // 目前只记录日志
                    log.info("讲座签到提醒：讲座「{}」将在1小时内开始，共有 {} 位用户需要签到", 
                            lecture.getTitle(), registrations.size());
                    reminderCount += registrations.size();
                }
            }
            
            if (reminderCount > 0) {
                log.info("讲座签到提醒发送完成，共提醒 {} 位用户", reminderCount);
            }
        } catch (Exception e) {
            log.error("发送讲座签到提醒失败", e);
        }
    }

    /**
     * 讲座数据统计
     * 每天凌晨2点执行，生成讲座相关的统计数据
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void generateLectureStatistics() {
        try {
            log.info("开始生成讲座统计数据...");
            
            Date now = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
            Date yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
            
            // 统计昨天的讲座数据
            QueryWrapper<Lecture> yesterdayQuery = new QueryWrapper<>();
            yesterdayQuery.ge("start_time", yesterday);
            yesterdayQuery.lt("start_time", now);
            
            List<Lecture> yesterdayLectures = lectureMapper.selectList(yesterdayQuery);
            
            int totalLectures = yesterdayLectures.size();
            int totalRegistrations = 0;
            int totalCheckIns = 0;
            
            for (Lecture lecture : yesterdayLectures) {
                QueryWrapper<LectureRegistration> regQuery = new QueryWrapper<>();
                regQuery.eq("lecture_id", lecture.getId());
                
                List<LectureRegistration> registrations = lectureRegistrationMapper.selectList(regQuery);
                
                totalRegistrations += registrations.stream()
                        .mapToInt(r -> r.getRegistrationStatus() != 2 ? 1 : 0) // 排除已取消
                        .sum();
                
                totalCheckIns += registrations.stream()
                        .mapToInt(r -> r.getRegistrationStatus() == 1 ? 1 : 0) // 只统计已签到
                        .sum();
            }
            
            double checkInRate = totalRegistrations > 0 ? 
                    (double) totalCheckIns / totalRegistrations * 100 : 0;
            
            log.info("昨日讲座统计：共举办 {} 场讲座，总报名 {} 人次，实际签到 {} 人次，签到率 {:.1f}%",
                    totalLectures, totalRegistrations, totalCheckIns, checkInRate);
            
            // 这里可以将统计数据保存到数据库或发送给相关人员
            
        } catch (Exception e) {
            log.error("生成讲座统计数据失败", e);
        }
    }

    /**
     * 清理过期数据
     * 每月1号凌晨4点执行，清理超过6个月的已结束讲座记录
     */
    @Scheduled(cron = "0 0 4 1 * ?")
    public void cleanUpExpiredLectures() {
        try {
            log.info("开始清理过期讲座数据...");
            
            Date now = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
            Date sixMonthsAgo = new Date(now.getTime() - 6L * 30 * 24 * 60 * 60 * 1000); // 6个月前
            
            // 查询6个月前已结束的讲座
            QueryWrapper<Lecture> expiredQuery = new QueryWrapper<>();
            expiredQuery.lt("end_time", sixMonthsAgo);
            expiredQuery.eq("lecture_status", 2); // 已结束状态
            
            List<Lecture> expiredLectures = lectureMapper.selectList(expiredQuery);
            
            int cleanedCount = 0;
            for (Lecture lecture : expiredLectures) {
                // 首先删除相关的报名记录
                QueryWrapper<LectureRegistration> regQuery = new QueryWrapper<>();
                regQuery.eq("lecture_id", lecture.getId());
                lectureRegistrationMapper.delete(regQuery);
                
                // 然后删除讲座记录（或者可以选择归档而不是删除）
                // lectureMapper.deleteById(lecture.getId());
                
                cleanedCount++;
            }
            
            log.info("过期讲座数据清理完成，共处理 {} 场讲座的数据", cleanedCount);
            
        } catch (Exception e) {
            log.error("清理过期讲座数据失败", e);
        }
    }
}